interface Trigger {
  /**
   * 计算准确的距离
   */
  getXyList(): void;
  updateXyList(): void;
  /**
   * 添加浏览器窗口大小监听事件
   */
  resize(): void;
  /**
   * 移除浏览器窗口大小监听事件
   */
  removeResize(): void;
  /**
   * 鼠标右击后开始计算菜单该出现的正确位置
   */
  computedDirection(
    target: HTMLElement,
    e: MouseEvent,
  ): void;
}

class Trigger implements Trigger {
  /**
   * 鼠标右键元素的祖根元素距离浏览器顶部和左边界的距离对象
   */
  private xyList = {
    top: 0,
    left: 0,
    width: 0,
    height: 0,
  }

  private target: HTMLElement = document.createElement("div");

  constructor(private positionEle: HTMLElement) {
    this.updateXyList();
  }

  getXyList(): void {
    const rect = this.positionEle?.getBoundingClientRect();
    this.xyList.top = (rect?.y as number) + scrollY;
    // 获取该组件根元素距离浏览器顶部和左边界的距离
    this.xyList.left = rect?.x! + scrollX;
    this.xyList.width = this.positionEle.offsetWidth;
    this.xyList.height = this.positionEle.offsetHeight;
  }

  updateXyList(): void {
    const beforeWid: number = this.xyList.width;
    const beforeHei: number = this.xyList.height;
    this.getXyList();
    if (this.target.innerHTML) {    
      const top: number = +this.target.style.top.replace('px', '');
      const left: number = +this.target.style.left.replace('px', '');
      const gapTop = top - beforeHei + this.xyList.height;
      if (gapTop >= 0 && top > 150) this.target.style.top = `${gapTop}px`;
      const gapLeft = left - beforeWid + this.xyList.width;     
      if (gapLeft >= 0 && left > 150) this.target.style.left = `${gapLeft}px`;
    }
  }

  resize(): void {
    globalThis.addEventListener("resize", this.updateXyList.bind(this));
  }

  removeResize(): void {
    globalThis.removeEventListener("resize", this.updateXyList.bind(this));
  }

  computedDirection(
    target: HTMLElement,
    e: MouseEvent,
  ): void {
    this.target = target;
    e.preventDefault();
    const yTop: number = e.clientY;
    const xLeft: number = e.clientX;
    let x: number = 0, // 鼠标距离该绑定元素顶部的距离
      y: number = 0; // 鼠标距离该绑定元素左边距的距离
    // 目标元素的自身高度
    const menuHei: number = target.offsetHeight;
    // 目标元素的自身宽度
    const menuWid: number = target.offsetWidth;
    // 边界处理
    if (this.xyList.top + this.xyList.height - yTop - scrollY < menuHei)
      y = scrollY + yTop - this.xyList.top > 0 ? scrollY + yTop - this.xyList.top - menuHei : 0;
    else 
      y = scrollY + yTop - this.xyList.top > 0 ? scrollY + yTop - this.xyList.top : 0;

    if (this.xyList.left + this.xyList.width - xLeft - scrollX < menuWid) 
      x = scrollX + xLeft - this.xyList.left > 0 ? scrollX + xLeft - this.xyList.left - menuWid : 0;
    else 
      x = scrollX + xLeft - this.xyList.left > 0 ? scrollX + xLeft - this.xyList.left : 0;
      
    target.style.top = y + 'px';
    target.style.left = x + 'px';
  }
}

export default Trigger